package com.example.apidocserver.domain.document.event.impl;

import com.example.apidocserver.application.dto.UserDocInfoDto;
import com.example.apidocserver.domain.document.dto.UploadMenuApiDto;
import com.example.apidocserver.domain.document.entity.ApiDocument;
import com.example.apidocserver.domain.document.entity.DocMenu;
import com.example.apidocserver.domain.document.event.DocumentDomainEvent;
import com.example.apidocserver.domain.document.service.ApiDocumentService;
import com.example.apidocserver.domain.document.service.DocMenuService;
import com.example.apidocserver.domain.user.entity.DocUsrHis;
import com.example.apidocserver.infrastructure.constants.SystemConstants;
import com.example.apidocserver.infrastructure.util.result.ParamException;
import com.example.apidocserver.infrastructure.util.user.UserDocAuthUtil;
import com.example.apidocserver.interfaces.vo.DocumentVo;
import com.example.apidocserver.interfaces.vo.OrderChangeVo;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

import static com.example.apidocserver.infrastructure.constants.SystemConstants.YES;

/**
 * 文档领域事件
 *
 * @author xyqlg
 */
@Service
public class DocumentDomainEventImpl implements DocumentDomainEvent {
    @Resource
    private ApiDocumentService apiDocumentService;

    @Resource
    private DocMenuService docMenuService;

    @Override
    public void setCurrentSpaceDocs(DocumentVo documentVo, DocUsrHis usrLastInfo) {
        UserDocInfoDto userDocInfoDto = UserDocAuthUtil.currentDocInfo();
        List<ApiDocument> apiDocuments = apiDocumentService.getReadDocuments(usrLastInfo.getSpaceId(),
                userDocInfoDto.isWriteFlag(), userDocInfoDto.isPublishFlag());
        documentVo.setDocuments(apiDocuments);

        if (CollectionUtils.isEmpty(apiDocuments)) {
            // 如果没有文档 则生成默认返回对象
            documentVo.setCurrentDocument(new ApiDocument(1).setPublished(YES));
        } else {
            ApiDocument currentDoc = apiDocuments.get(0);

            for (ApiDocument apiDocument : apiDocuments) {
                if (apiDocument.getId().equals(usrLastInfo.getDocId())) {
                    currentDoc = apiDocument;
                    break;
                }
            }

            documentVo.setCurrentDocument(currentDoc);
            usrLastInfo.setDocId(currentDoc.getId());
        }
    }

    @Override
    public void setCurrentMenu(DocumentVo documentVo, DocUsrHis usrLastInfo) {
        // 0.校验参数
        UserDocInfoDto userDocInfoDto = UserDocAuthUtil.currentDocInfo();
        documentVo.setCurrentMenus(Collections.emptyList());
        if (Objects.isNull(documentVo.getCurrentDocument().getId())) {
            return;
        }

        // 1.查询文档目录信息
        List<DocMenu> docMenuList = docMenuService.find(documentVo.getCurrentDocument().getId(),
                userDocInfoDto.isWriteFlag());
        if (CollectionUtils.isEmpty(docMenuList)) {
            return;
        }

        // 2.构建树结构
        List<DocMenu> topMenu = new ArrayList<>(docMenuList.size());
        documentVo.setCurrentMenus(topMenu).setApiIdSet( new TreeSet<>());
        Map<Integer, List<DocMenu>> idAndChildrenMap = new HashMap<>(docMenuList.size());
        for (DocMenu docMenu : docMenuList) {
            if (Objects.nonNull(docMenu.getApiId())) {
                documentVo.getApiIdSet().add(docMenu.getApiId());
            }
            if (Objects.isNull(docMenu.getParentId()) || SystemConstants.DATA_COMMON_ID.equals(docMenu.getParentId())) {
                // 上级id为通用数据id或为空，则为顶级层
                topMenu.add(docMenu);
            } else {
                // 非顶层目录
                if (idAndChildrenMap.containsKey(docMenu.getParentId())) {
                    // 添加到兄弟集合
                    idAndChildrenMap.get(docMenu.getParentId()).add(docMenu);
                } else {
                    // 添加到兄弟集合
                    List<DocMenu> brotherList = new LinkedList<>();
                    brotherList.add(docMenu);
                    idAndChildrenMap.put(docMenu.getParentId(), brotherList);
                }
            }
            // 设置子集
            setChildrenMenu(idAndChildrenMap, docMenu);
        }
        topMenu.sort(Comparator.comparing(DocMenu::getOrderNo));
        idAndChildrenMap.values().forEach(value -> value.sort(Comparator.comparing(DocMenu::getOrderNo)));
    }

    /**
     * 设置子集
     *
     * @param idAndChildrenMap id对应子集
     * @param docMenu          目录对象
     */
    private static void setChildrenMenu(Map<Integer, List<DocMenu>> idAndChildrenMap, DocMenu docMenu) {
        if (idAndChildrenMap.containsKey(docMenu.getId())) {
            docMenu.setChildren(idAndChildrenMap.get(docMenu.getId()));
        } else {
            List<DocMenu> childrenList = new LinkedList<>();
            docMenu.setChildren(childrenList);
            idAndChildrenMap.put(docMenu.getId(), childrenList);
        }
    }

    @Override
    public ApiDocument addDoc(ApiDocument document, DocUsrHis usrLastInfo) {
        Date date = new Date();
        document.setCreateTime(date).setUpdateTime(date);
        return apiDocumentService.insert(document);
    }

    @Override
    public ApiDocument findDocById(Integer docId) {
        if (Objects.isNull(docId)) {
            return null;
        }
        return apiDocumentService.queryById(docId);
    }


    @Override
    public DocMenu upsertDocMenu(DocMenu docMenu) {
        return docMenuService.upsertDocMenu(docMenu);
    }

    @Override
    public int orderChangeMenu(OrderChangeVo params) {
        return docMenuService.orderChangeMenu(params);
    }

    @Override
    public int deleteMenu(Integer id) {
        return docMenuService.deleteMenu(id);
    }

    @Override
    public void checkById(Integer docId) {
        ApiDocument apiDocument = apiDocumentService.queryById(docId);
        if (Objects.isNull(apiDocument)) {
            throw new ParamException("文档已不存在。");
        }
    }

    @Override
    public void insertMenuTrees(UploadMenuApiDto menuApiDto) {
        docMenuService.insertMenuTrees(menuApiDto);
    }
}
